package com.mkait.thief.util;

import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.data.redis.core.RedisTemplate;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Redis工具类
 */
@Component
public class RedisUtils {
    @Autowired
    private RedisTemplate redisTemplate;

    @Resource(name = "redisTemplate")
    private ValueOperations<String, String> valueOperations;

    @Resource(name = "redisTemplate")
    private ValueOperations<String, Object> valueObjectOperations;

    @Resource(name = "redisTemplate")
    private HashOperations<String, String, Object> hashOperations;

    @Resource(name = "redisTemplate")
    private ListOperations<String, Object> listOperations;

    @Resource(name = "redisTemplate")
    private SetOperations<String, Object> setOperations;

    @Resource(name = "redisTemplate")
    private ZSetOperations<String, Object> zSetOperations;

    /**  默认过期时长，单位：秒 */
    public final static long DEFAULT_EXPIRE = 60 * 60 * 24l;

    /**  不设置过期时长 */
    public final static long NOT_EXPIRE = -1;

    public void set(String key, Object value, long expire) {
        valueOperations.set(key, toJson(value));
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
    }

    public void set(String key, Object value) {
        set(key, value, DEFAULT_EXPIRE);
    }

    public <T> T get(String key, Class<T> clazz, long expire) {
        String value = valueOperations.get(key);
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
        return value == null ? null : fromJson(value, clazz);
    }

    public <T> T get(String key, Class<T> clazz) {
        return get(key, clazz, NOT_EXPIRE);
    }

    public String get(String key, long expire) {
        String value = valueOperations.get(key);
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
        return value;
    }

    public String get(String key) {
        return get(key, NOT_EXPIRE);
    }

    public void delete(String key) {
        redisTemplate.delete(key);
    }

    /**
     * Object转成JSON数据
     */
    private String toJson(Object object) {
        if (object instanceof Integer || object instanceof Long || object instanceof Float ||
                object instanceof Double || object instanceof Boolean || object instanceof String) {
            return String.valueOf(object);
        }
        return JSON.toJSONString(object);
    }

    /**
     * JSON数据，转成Object
     */
    private <T> T fromJson(String json, Class<T> clazz) {
        return JSON.parseObject(json, clazz);
    }

    public <T> T hGet(String key, String field, Class<T> clazz) {
        T value = (T) hashOperations.get(key, field);
        return value;
    }

    public <T> List<T> multiGet(String key,List<String> fields){
        List<T> value  = (List<T>)hashOperations.multiGet(key, fields);
        return value;
    }

    public <T> List<T> hVals(String key, Class<T> clazz) {

        List<T> value = (List<T>) hashOperations.values(key);
        return value;
    }

    public List<String> hFields(String key) {
        List<String> fields = (List<String>) hashOperations.keys(key);
        return fields;
    }

    public List<String> hFieldsList(String key) {
        return new ArrayList<>(hashOperations.keys(key));
    }
    public Long hSize(String key) {

        return hashOperations.size(key);
    }

    //hash set
    public void hSet(String key, String field, Object value, long expire){
        hashOperations.put(key, field, value);
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
    }

    public void hMset(String key, Map values, long expire){
        hashOperations.putAll(key, values);
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
    }

    //判断key是否存在
    public boolean exists(String key){
        return redisTemplate.hasKey(key);
    }

    //listOperations set 表头放
    public void lPush(String key, Object value, long expire){
        listOperations.leftPush(key, value);
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
    }
    public void lPushAll(String key, List values, long expire){
        listOperations.leftPushAll(key, values);
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
    }
    public void rPushAll(String key, Collection values, long expire){
        listOperations.rightPushAll(key, values);
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
    }

    //list getall
    public <T> List<T> lGetAll(String key, Class<T> clazz){
        List<T> objects = (List<T>) listOperations.range(key, 0, -1);

        return objects;
    }

    //list 指定index set值
    public void lSet(String key, int index, Object value, long expire){
        listOperations.set(key, index, value);
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
    }

    //获取第一个列表数据
    public <T> T lGetIndex(String key, int index, Class<T> clazz){
        T vaule = (T) listOperations.index(key, index);

        return vaule;
    }

    //获取list的长度
    public Long getListSize(String key){
        return  listOperations.size(key);
    }
    //获取list区间数据
    public <T> List<T> lGetAllRang(String key, Long start,Long end){
        List<T> objects = (List<T>) listOperations.range(key, start, end);

        return objects;
    }

    //批量获取
    public <T> List<T> multiGet(List<String> keys) {
        List<T> values = (List<T>) valueObjectOperations.multiGet(keys);
        return values;
    }
    //对象保存
    public void setObject(String key, Object value, long expire) {
        if (expire != NOT_EXPIRE) {
            valueObjectOperations.set(key, value,expire, TimeUnit.SECONDS);
        }else {
            valueObjectOperations.set(key, value);
        }
    }

    //对象获取
    public <T> T getObject(String key) {
        T value = (T) valueObjectOperations.get(key);
        return value;
    }

    public void multiSetObject(Map<String, Object> map, long expire) {
        valueObjectOperations.multiSet(map);
        if (expire != NOT_EXPIRE) {
            map.keySet().forEach(key ->{
                redisTemplate.expire(key, expire, TimeUnit.SECONDS);
            });

        }
    }

    public List<Object> hMGet(List<String> keys, List<String> fields){
        List<Object> results = redisTemplate.executePipelined(new RedisCallback<Object>() {
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                for(int i = 0; i < keys.size(); i++) {
                    connection.hGet(keys.get(i).getBytes(), fields.get(i).getBytes());
                }
                return null;
            }
        });
        return results;
    }


    public List<Long> hMGetSize(List<String> keys){
        List<Long> results = redisTemplate.executePipelined(new RedisCallback<Long>() {
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                for(int i = 0; i < keys.size(); i++) {
                    connection.hLen(keys.get(i).getBytes());
                }
                return null;
            }
        });
        return results;
    }


    /**
     *
     * @param keys 删除key 可变参数
     */
    public void del(String ...keys){
        if(keys!=null&&keys.length>0) {
            redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(keys));
        }
    }

    public void delKeys(List<String> keys){
        if(keys!=null&&keys.size()>0) {
            redisTemplate.delete(keys);
        }
    }

    public void expire(String key,long expire){
        redisTemplate.expire(key, expire, TimeUnit.SECONDS);
    }

    public void hDel(String key,String ... subKeys){
        if(key!=null && key.length()>0 && subKeys != null && subKeys.length > 0) {
            redisTemplate.opsForHash().delete(key,subKeys);
        }
    }

}
